/*
Copyright [2023] [fuwen_soft]
*/
package vip.xiaonuo.modular.xyuser.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import vip.xiaonuo.core.consts.CommonConstant;
import vip.xiaonuo.core.context.constant.ConstantContextHolder;
import vip.xiaonuo.core.context.login.LoginContextHolder;
import vip.xiaonuo.core.enums.CommonStatusEnum;
import vip.xiaonuo.core.exception.ServiceException;
import vip.xiaonuo.core.factory.PageFactory;
import vip.xiaonuo.core.pojo.login.SysLoginUser;
import vip.xiaonuo.core.pojo.page.PageResult;
import vip.xiaonuo.core.util.PoiUtil;
import vip.xiaonuo.modular.xylogyauth.entity.XyLogyAuth;
import vip.xiaonuo.modular.xylogyauth.service.XyLogyAuthService;
import vip.xiaonuo.modular.xyuser.entity.XyUser;
import vip.xiaonuo.modular.xyuser.enums.XyUserExceptionEnum;
import vip.xiaonuo.modular.xyuser.form.WechatForm;
import vip.xiaonuo.modular.xyuser.form.WechatInfoForm;
import vip.xiaonuo.modular.xyuser.mapper.XyUserMapper;
import vip.xiaonuo.modular.xyuser.param.XyUserParam;
import vip.xiaonuo.modular.xyuser.service.XyUserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.modular.xyuser.vo.UserCodeVo;
import vip.xiaonuo.sys.core.cache.UserCache;
import vip.xiaonuo.sys.core.jwt.JwtPayLoad;
import vip.xiaonuo.sys.core.jwt.JwtTokenUtil;
import vip.xiaonuo.sys.core.msg.Result;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;

import static vip.xiaonuo.sys.core.msg.ResultUtils.success;

/**
 * 用户信息service接口实现类
 *
 * @author yanwei
 * @date 2023-05-05 15:44:27
 */
@Service
@Slf4j
public class XyUserServiceImpl extends ServiceImpl<XyUserMapper, XyUser> implements XyUserService {

    @Autowired
    private WxMaService wxMaService;

    @Resource
    private UserCache userCache;
    @Override
    public PageResult<XyUser> page(XyUserParam xyUserParam) {
        QueryWrapper<XyUser> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotNull(xyUserParam)) {

            // 根据 查询
            if (ObjectUtil.isNotEmpty(xyUserParam.getOpenId())) {
                queryWrapper.lambda().eq(XyUser::getOpenId, xyUserParam.getOpenId());
            }
            // 根据微信昵称 查询
            if (ObjectUtil.isNotEmpty(xyUserParam.getNickName())) {
                queryWrapper.lambda().eq(XyUser::getNickName, xyUserParam.getNickName());
            }
            // 根据微信头像 查询
            if (ObjectUtil.isNotEmpty(xyUserParam.getImgUrl())) {
                queryWrapper.lambda().eq(XyUser::getImgUrl, xyUserParam.getImgUrl());
            }
            // 根据手机号 查询
            if (ObjectUtil.isNotEmpty(xyUserParam.getPhoneNumber())) {
                queryWrapper.lambda().eq(XyUser::getPhoneNumber, xyUserParam.getPhoneNumber());
            }
            // 根据谱号_唯一标识 查询
            if (ObjectUtil.isNotEmpty(xyUserParam.getGenealogyHost())) {
                queryWrapper.lambda().eq(XyUser::getGenealogyHost, xyUserParam.getGenealogyHost());
            }

            // 根据谱号_唯一标识 查询
            if (ObjectUtil.isNotEmpty(xyUserParam.getIsSupport())) {
                queryWrapper.lambda().eq(XyUser::getIsSupport, xyUserParam.getIsSupport());
            }
        }
        queryWrapper.lambda().orderByDesc(XyUser::getCreateTime);
        return new PageResult<>(this.page(PageFactory.defaultPage(), queryWrapper));
    }

    @Override
    public List<XyUser> list(XyUserParam xyUserParam) {
        return this.list();
    }

    @Override
    public void add(XyUserParam xyUserParam) {
        XyUser xyUser = new XyUser();
        BeanUtil.copyProperties(xyUserParam, xyUser);
        this.save(xyUser);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<XyUserParam> xyUserParamList) {
        xyUserParamList.forEach(xyUserParam -> {
            this.removeById(xyUserParam.getId());
        });
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(XyUserParam xyUserParam) {
        XyUser xyUser = this.queryXyUser(xyUserParam);
        BeanUtil.copyProperties(xyUserParam, xyUser);
        this.updateById(xyUser);
    }

    @Override
    public XyUser detail(XyUserParam xyUserParam) {
        return this.queryXyUser(xyUserParam);
    }

    /**
     * 获取用户信息
     *
     * @author yanwei
     * @date 2023-05-05 15:44:27
     */
    private XyUser queryXyUser(XyUserParam xyUserParam) {
        XyUser xyUser = this.getById(xyUserParam.getId());
        if (ObjectUtil.isNull(xyUser)) {
            throw new ServiceException(XyUserExceptionEnum.NOT_EXIST);
        }
        return xyUser;
    }

    @Override
    public void export(XyUserParam xyUserParam) {
        List<XyUser> list = this.list(xyUserParam);
        PoiUtil.exportExcelWithStream("SnowyXyUser.xls", XyUser.class, list);
    }

    @Override
    public Result<UserCodeVo> loginByCode(String code) {
        UserCodeVo userCodeVo = new UserCodeVo();
        try {
            WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(code);
            XyUser tbUser = getOne(Wrappers.<XyUser>lambdaQuery().eq(XyUser::getOpenId, session.getOpenid()));
            if (Objects.nonNull(tbUser)) {
                userCodeVo.setToken(getTokenStr(tbUser));
                userCodeVo.setWxMaJscode2SessionResult(session);
                return success(userCodeVo);
            }
            log.info(session.getSessionKey());
            log.info(session.getOpenid());
            userCodeVo.setWxMaJscode2SessionResult(session);
            return success(userCodeVo);
        } catch (WxErrorException e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    @Override
    public String login(WechatForm wechatForm) {

        //   WxMaUserInfo userInfo = wxMaService.getUserService().getUserInfo(wechatInfoForm.getSessionKey(), wechatInfoForm.getEncryptedData(), wechatInfoForm.getIv());
        String openId = wechatForm.getOpenId();
        // 判定,是否是二次用户
        XyUser tbUser = getOne(Wrappers.<XyUser>lambdaQuery().eq(XyUser::getOpenId, openId));
        if (Objects.nonNull(tbUser)) {
            return getTokenStr(tbUser);
        }
        tbUser = new XyUser(wechatForm);
        save(tbUser);
        return getTokenStr(tbUser);
    }

    @SneakyThrows
    @Override
    public void getPhoneNumber(String code) {
        Long userId = LoginContextHolder.me().getSysLoginUser().getId();
        XyUser xyUser = getById(userId);
        //wxMaService.getUserService().getPhoneNoInfo()
        xyUser.setPhoneNumber(wxMaService.getUserService().getNewPhoneNoInfo(code).getPurePhoneNumber());
        updateById(xyUser);
        // 手机号绑定后，需要完善下 auth 的权限信息
        bindAuthFlag(xyUser);
    }

    @SneakyThrows
    @Override
    public void getNewPhoneNumber(WechatInfoForm wechatInfoForm) {
        Long userId = LoginContextHolder.me().getSysLoginUser().getId();
        XyUser xyUser = getById(userId);
        WxMaPhoneNumberInfo newPhoneNoInfo = wxMaService.getUserService().getNewPhoneNoInfo(wechatInfoForm.getCode());
        xyUser.setPhoneNumber(newPhoneNoInfo.getPurePhoneNumber());
        updateById(xyUser);
        bindAuthFlag(xyUser);

    }

    private static void bindAuthFlag(XyUser xyUser) {
        // 手机号绑定后，需要完善下 auth 的权限信息
        XyLogyAuthService xyLogyAuthService = SpringUtil.getBean(XyLogyAuthService.class);
        // 绑定下
        xyLogyAuthService.update(Wrappers.<XyLogyAuth>lambdaUpdate().isNull(XyLogyAuth::getUserId).eq(XyLogyAuth::getPhone, xyUser.getPhoneNumber()).set(XyLogyAuth::getUserId, xyUser.getId()).set(XyLogyAuth::getReMark,"已注册"));
    }

    public String getTokenStr(XyUser xyUser){
        //构造jwtPayLoad
        JwtPayLoad jwtPayLoad = new JwtPayLoad(Long.valueOf(xyUser.getId()), xyUser.getOpenId());

        //生成token
        String token = JwtTokenUtil.generateToken(jwtPayLoad);
        this.cacheLoginUser(jwtPayLoad,this.genSysLoginUser(xyUser));
        return token;
    }

    /**
     * 构造 登录信息
     * @param
     * @return
     */
    private SysLoginUser genSysLoginUser(XyUser user) {
        SysLoginUser sysLoginUser = new SysLoginUser();
        BeanUtil.copyProperties(user, sysLoginUser);
        //LoginUserFactory.fillLoginUserInfo(sysLoginUser);
        return sysLoginUser;
    }

    /**
     * 缓存token与登录用户信息对应, 默认2个小时
     *
     * @author xuyuxiang
     * @date 2020/3/13 14:51
     */
    private void cacheLoginUser(JwtPayLoad jwtPayLoad, SysLoginUser sysLoginUser) {
        String redisLoginUserKey = jwtPayLoad.getUuid();
        userCache.put(redisLoginUserKey, sysLoginUser, Convert.toLong(ConstantContextHolder.getSessionTokenExpireSec()));
    }

}
